/*
    Copyright (c) 2007, Arpit Mathur 
    Used by permission by Drumbeat Insight
    
    Based on the work of (between others):Akeem Philbert, Jesse Warden, Xavi Beumala, Renaun 
	Erickson, Carlos Rovira)
	
	All rights reserved.
	Redistribution and use in source and binary forms, with or without modification, are permitted provided that the 
	following conditions are met:
	
	    * Redistributions of source code must retain the above copyright notice, this list of conditions and the following 
		  disclaimer.
	    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the 
		  following disclaimer in the documentation and/or other materials provided with the distribution.
	    * Neither the name of the Akeem Philbert nor the names of its contributors may be used to endorse or promote 
		  products derived from this software without specific prior written permission.
	
	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 
	INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
	DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
	SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
	SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
	WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
	OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package com.drumbeatinsight.services.wordpress {
	
	import com.drumbeatinsight.rpc.core.RPCEvent;
	import com.drumbeatinsight.rpc.xmlrpc.XMLRPCObject;
	import com.drumbeatinsight.data.DataField;
	
	import mx.collections.ArrayCollection;
	import mx.rpc.events.ResultEvent;
	
	public class WordPress extends XMLRPCObject {
		
		public static const ENTRIES_RECIEVED:String = "entriesRecieved";
		public static const CATEGORIES_RECIEVED:String = "categoriesRecieved";
	
		private var _blogURL:String;
		private var _blogid:String = "0";
		private var _user:String;
		private var _password:String;
		
		[Bindable]
		public var resultData:Object;
		
		public var _entries:Array;
		public var _categories:Array;
		
		private var _count:int;
		
		private var _setCustomFieldsOnBlogEntry:Boolean = true;
		
		[Bindable]
		public var entries:ArrayCollection = new ArrayCollection(new Array());
		
		[Bindable]
		public var entry:BlogEntry;
		
		[Bindable]
		public var category:BlogCategory;
		
		[Bindable]
		public var categories:ArrayCollection;
		
		[Bindable]
		public var post:BlogEntry;
		
		// this will hold the formatting columns from the DataTables class
		public var formattingOptions:Array = new Array();
		
		public function WordPress(blogURL:String, rpcfile:String, blogid:String, 
									user:String, password:String) {
			_blogid = blogid;
			_user = user;
			_password = password;
			
			this.endpoint = blogURL;
			this.destination = rpcfile;
			this.contentType = "application/xml";
		}
		
		/**
		If true then any custom fields will be added dynamically to the blog entry object in addition
		to them being defined in the customFields property. 
		
		Blog entries that do not have a custom field set will be added conditionally to the object 
		<b>if</b> any of the entries returned has a custom field set. The entries that do not have 
		the custom fields set will contain the property but the value will be an empty string.
		*/
		public function set setCustomFieldsOnBlogClass(value:Boolean):void {
			_setCustomFieldsOnBlogEntry = value;
		}
		
		public function callFunction(method:String, args:Array):void{
			this.makeCall(method,args)
		}
		
		/**
		Submit Post
		*/
		public function newPost(post:*=null):void {
			
			if (post==null) {
				post = this.post;
			}
			//var newPost:IXMLRPCStruct = new IXMLRPCStruct();
			//makeCall("metaWeblog.newPost",[_blogid,_user,_password,post,publish]);
			makeCall("metaWeblog.newPost",[_blogid,_user,_password,post,true]);
		}
		
		/**
		Get Posts most recent first. 
		Includes all custom fields on a post by default. Does not include draft and private posts like 
		You need to use the xmlrpc file that has the "jp_" methods in it
		*/
		public function getPosts(count:Number, includeCustomFields:Boolean = true):void {
			
			if (includeCustomFields) {
				makeCall("jp.getPosts",[_blogid,_user,_password,count]);
			}
			else {
				// this method returns private and draft posts in wordpress - may not be what you want
				makeCall("metaWeblog.getRecentPosts",[_blogid,_user,_password,count])
			}
		}
		
		/**
		Get a Single Post 
		Includes wordpress custom fields by default.
		You need to use the xmlrpc file that has the "jp_" methods in it
		*/
		public function getPost(id:Number, includeCustomFields:Boolean = true):void {
			
			if (includeCustomFields) {
				makeCall("jp.getPost",[id, _user, _password]);
			}
			else {
				makeCall("metaWeblog.getPost",[id, _user, _password])
			}
		}
		
		/**
		Get Posts by Category 
		Pass in the name of the category (case-insensitive) and count. Both params are optional.
		You need to use the xmlrpc file that has the "jp_" methods in it
		Should add "sort by" and rangeFrom and rangeTo parameters. Not yet implemented
		*/
		public function getPostsByCategory(category:String, count:Number = 0):void {
			makeCall("jp.getPostsByCategory",[_blogid, _user, _password, category, count])
		}
		
		public function getCategories():void {
			makeCall("metaWeblog.getCategories", [_blogid, _user, _password])
		}
		
		override protected function onResult(evt:RPCEvent):void {
			var resultevent:ResultEvent = ResultEvent(evt.data);
			resultData = resultevent.result;
			super.onResult(evt);
		}
		
		public function getResultAsEntries():ArrayCollection {
			var customFieldsList:Array = new Array();
			var entry:BlogEntry;
			
			_entries = new Array();
			
			// loop through each item in the result set and 
			// add custom fields 
			// and format the value if needed
			// and set the default value if needed
			for (var a:String in resultData) {
				
				entry = new BlogEntry();
				var res:Object = resultData[a];
				var customFields:Object = res.wp_custom_fields;
				
				entry.categories = res.categories
				entry.dateCreated = res.dateCreated
				entry.description = res.description
				entry.link = res.link
				entry.mt_allow_comments = res.mt_allow_comments
				entry.mt_allow_pings = res.mt_allow_pings
				entry.mt_excerpt = res.mt_excerpt
				entry.mt_text_more = res.mt_text_more
				entry.permaLink = res.permaLink
				entry.postid = res.postid
				entry.title = res.title
				entry.userid = res.userid
				entry.wp_author_display_name = res.wp_author_display_name
				entry.wp_author_id = res.wp_author_id
				entry.wp_slug = res.wp_slug
				
				// loop through the custom fields and add them to the entry
				for (var b:String in customFields){
					if (!entry.wp_custom_fields) {
						entry.wp_custom_fields = new Object();
					}
					
					// add custom fields on BlogEntry object
					if (_setCustomFieldsOnBlogEntry) {
						entry[b] = customFields[b] as Array;
						customFieldsList.push(b);
					}
					
					// always define on here so we can differentiate if we need to
					entry.wp_custom_fields[b] = customFields[b] as Array;
				}
				
				_entries.push(entry);
			}
			
			// add any custom fields
			_entries = addCustomFields(_entries, customFieldsList);
			
			// format any fields
			_entries = formatDataFields(_entries);
			
			// ************* CUSTOM FIELDS *******************
			// when we add our custom fields onto one blog entry class 
			// then we have to add them to all blog entries to prevent #1009 property not found errors
			// we should let the user set the default value in the columns object
/* 			if (customFieldsList.length > 0 && _setCustomFieldsOnBlogEntry) {

				// loop through each post in the array
				for (var i:int=0;i<_entries.length;i++) {
					entry = _entries[i];
					
					// add any custom fields onto the entry that exist on other entries
					for (var j:int=0;j<customFieldsList.length;j++) {
						if (!entry[customFieldsList[j]]) {
							entry[customFieldsList[j]] = null;
						}
					}
				}
			}
 */			
			// ************* FORMATTING *******************
			// right here we loop through all the columns in the formattingArray
			// loop through each item in the columns array
			// if column is defined then format it
			// entry[column[i].fieldName] = formattedValue;
			// something like that
/* 			if (formattingOptions.length > 0) {
				var optionsObject:DataField;
				
				// loop through each post in the array
				for (var k:int=0;k<_entries.length;k++) {
					entry = _entries[k];
					
					// loop through each column and see if we need to do any formatting
					for (var c:int=0;c<formattingOptions.length;c++) {
						optionsObject = formattingOptions[c];
						
						// check if field exists on entry before we do anything
						if (entry.hasOwnProperty(optionsObject.dataField)) {
						
							// specify a default value if user wants something other than null
							if (optionsObject.defaultValue!=null && entry[optionsObject.dataField]==null) {
								entry[optionsObject.dataField] = optionsObject.defaultValue;
							}
							
							// format html to work in flash text fields
							if (optionsObject.formatAsHTML)  {
								entry[optionsObject.dataField] = Utils.formatText(entry[optionsObject.dataField]);
							}
							
							// add additional use cases here
						}
					}
				}
			} */
	
			
			entries = new ArrayCollection(_entries);
			
			return entries;
		}
		
		public function getResultAsEntry(index:Number = 0):BlogEntry {
			var res:Object;
			
			if (resultData is Array) {			
				res = resultData[index];
			}
			else {
				res = resultData;
			}
			
			entry = new BlogEntry();
			var customFields:Object = res.wp_custom_fields;
			
			entry.categories = res.categories
			entry.dateCreated = res.dateCreated
			entry.description = Utils.formatText(res.description);
			entry.link = res.link
			entry.mt_allow_comments = res.mt_allow_comments
			entry.mt_allow_pings = res.mt_allow_pings
			entry.mt_excerpt = res.mt_excerpt
			entry.mt_text_more = res.mt_text_more
			entry.permaLink = res.permaLink
			entry.postid = res.postid
			entry.title = res.title
			entry.userid = res.userid
			entry.wp_author_display_name = res.wp_author_display_name
			entry.wp_author_id = res.wp_author_id
			entry.wp_slug = res.wp_slug
			
			// ************* CUSTOM FIELDS *******************
			for(var b:String in customFields){
				if (!entry.wp_custom_fields) {
					entry.wp_custom_fields = new Object();
				}
				
				// define custom fields on BlogEntry object
				if (_setCustomFieldsOnBlogEntry) {
					entry[b] = customFields[b] as Array;
				}
				
				// always define on here so we can differentiate if we need to
				entry.wp_custom_fields[b] = customFields[b] as Array;
			}
		

			// ************* FORMATTING *******************
			// right here we loop through all the columns in the formattingArray
			// loop through each item in the columns array
			// if column is defined then format it
			// entry[column[i].fieldName] = format	
			if (formattingOptions.length > 0) {
				var optionsObject:DataField;
				// loop through each column and see if we need to do any formatting
				for (var c:int=0;c<formattingOptions.length;c++) {
					optionsObject = formattingOptions[c];
					
					// check if field exists on entry before we do anything
					if (entry.hasOwnProperty(optionsObject.dataField)) {
					
						// specify a default value if user wants something other than null
						if (optionsObject.defaultValue!=null && entry[optionsObject.dataField]==null) {
							entry[optionsObject.dataField] = optionsObject.defaultValue;
						}
						
						// format html to work in flash text fields
						if (optionsObject.formatAsHTML)  {
							entry[optionsObject.dataField] = Utils.formatText(entry[optionsObject.dataField]);
						}
						
						// add additional use cases here
					}
				}
			}

			return entry;	
		}
		
		public function getResultAsCategories():ArrayCollection {
			_categories = new Array();
			
			for (var a:String in this.resultData) {
				var res:Object = this.resultData[a];
				var cat:BlogCategory = new BlogCategory();
				
				cat.categoryId = res.categoryId;
				cat.categoryName = res.categoryName;
				cat.description = res.description;
				cat.htmlUrl = res.htmlUrl;
				cat.parentId = res.parentId;
				cat.rssUrl = res.rssUrl;
				
				cat.label  = res.categoryName;
				
				_categories.push(cat);
			}
			
			categories = new ArrayCollection(_categories);
			
			return categories;
		}
		

		// ************* CUSTOM FIELDS *******************
		// when we add our custom fields onto one blog entry class 
		// then we have to add them to all blog entries to prevent #1009 property not found errors
		// we should let the user set the default value in the columns object
		public function addCustomFields(items:Array, customFieldsList:Array):Array {
			var entry:BlogEntry;
			var field:String;
			var exists:Boolean;
			
			if (customFieldsList.length > 0 && _setCustomFieldsOnBlogEntry) {

				// loop through each post in the array
				for (var i:int=0;i<_entries.length;i++) {
					entry = items[i];
					
					// add any custom fields onto the entry that exist on other entries but not on this one
					for (var j:int=0;j<customFieldsList.length;j++) {
						field = customFieldsList[j];
						exists = entry.hasOwnProperty(field);
						//trace("Data Component: checking field '" + field + "'");
						
						// if the field does not exist on the entry then add it
						// we format it or set the default value in the format field method
						if (exists==false) {
							//trace("Data Component: defining custom field '" + field + "'");
							entry[field] = null;
						}
					}
				}
			}
			return items;
		}
		
		// ************* FORMATTING *******************
		// right here we loop through all the columns in the formattingArray
		// loop through each item in the columns array
		// if column is defined then format it
		// entry[column[i].fieldName] = format	
		public function formatDataFields(items:Array):Array {
			var entry:BlogEntry;
			var optionsObject:DataField;
			var field:String;
			var fieldValue:String;
			
			if (formattingOptions.length > 0) {
				
				if (items==null) {
					return new Array();
				}
				
				// loop through each post in the array
				for (var k:int=0;k<items.length;k++) {
					entry = items[k] as BlogEntry;
					
					if (entry==null) {
						trace("Data Component: We can't convert an object into a Blog Entry. Use BlogEntry instead of Object.");
					}
					
					// loop through each column and see if we need to do any formatting
					for (var c:int=0;c<formattingOptions.length;c++) {
						optionsObject = formattingOptions[c];
						field = optionsObject.dataField;
						
						// check if field exists on entry before we do anything
						if (field!=null && entry.hasOwnProperty(field)) {
							//trace("\nData Component: Checking format options on field '" + field + "'");
							// specify a default value if user wants something other than null
							if (optionsObject.defaultValue!=null && entry[field]==null) {
								//trace("Data Component: Setting default value to '" + optionsObject.defaultValue + "'");
								fieldValue = optionsObject.defaultValue;
							}
							
							// format html to work in flash text fields
							if (optionsObject.formatAsHTML) {
								//trace("Data Component: Formatting to compatible html");
								fieldValue = Utils.formatText(entry[field]);
							}
							
							// get the markup of an image tag
							if (optionsObject.findImageTag) {
								//trace("Data Component: Parsing html to find image tag");
								fieldValue = Utils.getImageHTML(entry[field]);
							}
							
							// get the path to the source of an image in image tag markup
							if (optionsObject.findImagePath) {
								//trace("Data Component: Parsing html to find image path");
								fieldValue = Utils.getImageSource(entry[field]);
							}
							
							if (optionsObject.labelFunction!=null) {
								fieldValue = optionsObject.labelFunction(entry, entry[field], fieldValue);
							}
							
							// add additional use cases here
							// add formatters here
							
							entry[field] = fieldValue;
						}
					}
				}
			}
			return items;
		}
		
	} // end of class
}